17. Using Mockito to Write Navigation Tests

L5 P3 A11 Using Mockito To Write Navigation Tests

As you saw in the video, you'll write an integration test that includes the Navigation component. In doing so, you'll create a mock, using Mockito.

Step 1: Add Gradle Dependencies

  1. Add the gradle dependencies:

app/build.gradle

    // Dependencies for Android instrumented unit tests
    androidTestImplementation "org.mockito:mockito-core:$mockitoVersion"

    androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito:$dexMakerVersion" 

    androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"

Step 2: Create TasksFragmentTest

  1. Open TasksFragment.
  2. Right click on the TasksFragment class name and select Generate then Test. Create a test in the androidTest source set.
  3. Copy over this code to the TasksFragmentTest:

TasksFragmentTest.kt

@RunWith(AndroidJUnit4::class)
@MediumTest
@ExperimentalCoroutinesApi
class TasksFragmentTest {

    private lateinit var repository: TasksRepository

    @Before
    fun initRepository() {
        repository = FakeAndroidTestRepository()
        ServiceLocator.tasksRepository = repository
    }

    @After
    fun cleanupDb() = runBlockingTest {
        ServiceLocator.resetRepository()
    }

}
  1. Add the test clickTask_navigateToDetailFragmentOne:

TasksFragmentTest.kt

    @Test
    fun clickTask_navigateToDetailFragmentOne() = runBlockingTest {
        repository.saveTask(Task("TITLE1", "DESCRIPTION1", false, "id1"))
        repository.saveTask(Task("TITLE2", "DESCRIPTION2", true, "id2"))

        // GIVEN - On the home screen
        val scenario = launchFragmentInContainer<TasksFragment>(Bundle(), R.style.AppTheme)

    }
  1. Use Mockito's mock function to create a mock:

TasksFragmentTest.kt

 val navController = mock(NavController::class.java)
  1. Make your new mock the fragment's NavController:

TasksFragmentTest.kt

scenario.onFragment {
    Navigation.setViewNavController(it.view!!, navController)
}
  1. Add the code to click on the item in the RecyclerView that has the text "TITLE1":

TasksFragmentTest.kt

// WHEN - Click on the first list item
        onView(withId(R.id.tasks_list))
            .perform(RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
                hasDescendant(withText("TITLE1")), click()))

RecyclerViewActions is part of the espresso-contrib library and lets you perform Espresso actions on a RecyclerView.

  1. Verify that navigate was called, with the correct argument:

TasksFragmentTest.kt

// THEN - Verify that we navigate to the first detail screen
verify(navController).navigate(
    TasksFragmentDirections.actionTasksFragmentToTaskDetailFragment( "id1")

The complete test looks like this:

TasksFragmentTest.kt

@Test
fun clickTask_navigateToDetailFragmentOne() = runBlockingTest {
    repository.saveTask(Task("TITLE1", "DESCRIPTION1", false, "id1"))
    repository.saveTask(Task("TITLE2", "DESCRIPTION2", true, "id2"))

    // GIVEN - On the home screen
    val scenario = launchFragmentInContainer<TasksFragment>(Bundle(), R.style.AppTheme)

        val navController = mock(NavController::class.java)
    scenario.onFragment {
        Navigation.setViewNavController(it.view!!, navController)
    }

    // WHEN - Click on the first list item
    onView(withId(R.id.tasks_list))
        .perform(RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
            hasDescendant(withText("TITLE1")), click()))


    // THEN - Verify that we navigate to the first detail screen
    verify(navController).navigate(
        TasksFragmentDirections.actionTasksFragmentToTaskDetailFragment( "id1")
    )
}
  1. As always, remember to run your test!

In summary, to test navigation you can:

  1. Use Mockito to create a NavController mock.
  2. Attach that mocked NavController to the fragment.
  3. Verify that navigate was called with the correct action and parameter(s).

Optional Step: Optional, write clickAddTaskButton_navigateToAddEditFragment

To see if you can write a navigation test yourself, try this:

  1. Write the test clickAddTaskButton_navigateToAddEditFragment which checks that if you click on the + FAB, you navigate to the AddEditTaskFragment.